package com.demo.util;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.demo.exception.SystemException;
import com.google.protobuf.ByteString;
import com.google.protobuf.Descriptors;
import com.google.protobuf.GeneratedMessage;
@SuppressWarnings("all")
public class ProtobufUtils {
	private Log logger = LogFactory.getLog(ProtobufUtils.class);

	public static byte[] serialize(GeneratedMessage.Builder obj) throws Exception {
		ByteArrayOutputStream baos = null;
		try {
			baos = new ByteArrayOutputStream();

			obj.build().writeTo(baos);

			byte[] arrayOfByte = baos.toByteArray();
			return arrayOfByte;
		} finally {
			if (baos != null)
				baos.close();
		}
	}

	public static GeneratedMessage.Builder deserialize(Object srcObj, GeneratedMessage.Builder descObj) throws Exception {
		try {
			if ((srcObj instanceof byte[])) {
				descObj.mergeFrom((byte[]) srcObj);
			} else if ((srcObj instanceof ByteString)) {
				descObj.mergeFrom((ByteString) srcObj);
			} else if (!(srcObj instanceof List)) {
				Set srcMethodSet = org.apache.commons.beanutils.BeanUtils.describe(srcObj).keySet();

				for (Descriptors.FieldDescriptor fieldDescriptor : descObj.getDescriptorForType().getFields()) {
					Object value = null;

					if (srcMethodSet.contains(fieldDescriptor.getName())) {
						value = PropertyUtils.getProperty(srcObj, fieldDescriptor.getName());
					}

					if (value != null) {
						if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.STRING)
							value = BeanUtils.convert(value, String.class);
						else if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.INT)
							value = BeanUtils.convert(value, Integer.class);
						else if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.BYTE_STRING) {
							if ((value instanceof byte[]))
								value = ByteString.copyFrom((byte[]) value);
							else
								throw new SystemException("protobuf反射错误:[" + fieldDescriptor.getName() + "]为byteString类型,必须输入byte[]数组格式");
						} else if (fieldDescriptor.getJavaType() != Descriptors.FieldDescriptor.JavaType.MESSAGE) {
							throw new SystemException("protobuf反射错误:[" + fieldDescriptor.getName() + "]未知的类型"
									+ fieldDescriptor.getJavaType());
						}

					}

					if (fieldDescriptor.isRepeated())
						continue;
					if (value != null) {
						descObj.setField(fieldDescriptor, value);
					} else {
						if ((!fieldDescriptor.isRequired())
								|| (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE)) {
							continue;
						}
						descObj.setField(fieldDescriptor, fieldDescriptor.getDefaultValue());
					}
				}

			}

			return descObj;
		} catch (Exception e) {
			throw new SystemException("protobuf反序列化出错!" + e.getMessage());
		}
	}

	public static GeneratedMessage.Builder deserialize(Object srcObj, Class<? extends GeneratedMessage> clz) throws Exception {
		Method method = clz.getMethod("newBuilder", new Class[0]);
		GeneratedMessage.Builder descObj = (GeneratedMessage.Builder) method.invoke(clz, new Object[0]);

		return deserialize(srcObj, descObj);
	}

	public static Map<String, Object> toProtobuf(GeneratedMessage.Builder protobufObj) {
		Map result = new HashMap();

		return result;
	}
}